/********************************************
 * 功能说明: 
 * 模块名称: 
 * 系统名称: 
 * 软件版权: Frank
 * 系统版本: 1.0.0
 * 开发人员: Frank
 * 开发时间: 2019/12/3 16:52
 * 审核人员: 
 * 相关文档: 
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.spring.arch.uaa.oauth2.dynamic;

import com.spring.arch.common.security.SecurityLog;
import com.spring.arch.common.utils.HttpUtils;
import com.spring.arch.common.security.SecurityLog;
import com.spring.arch.common.utils.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 加载URL-ROLE元数据
 * - 用于动态权限控制
 *
 * @author Frank
 * @version 1.0.0.1
 * @since 2019/12/3 16:52
 */
@Slf4j
public class DynamicallyUrlSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private Map<UrlPattern, Collection<ConfigAttribute>> requestMap;
    private String excludeAuthUrl;

    public DynamicallyUrlSecurityMetadataSource(Map<UrlPattern, Collection<ConfigAttribute>> requestMap, String excludeAuthUrl) {
        this.requestMap = requestMap;
        this.excludeAuthUrl = excludeAuthUrl;
    }

    /**
     * 在我们初始化的权限数据中找到对应当前url的权限数据
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        FilterInvocation fi = (FilterInvocation) object;
        HttpServletRequest request = fi.getRequest();
        // 获取请求IP
        final String clientIP = HttpUtils.getClientIP(request);
        final String url = fi.getRequestUrl();
        final String httpMethod = fi.getRequest().getMethod();
        // 排除静态资源
        if (StringUtils.isNotBlank(excludeAuthUrl)) {
            final String[] antPatterns = StringUtils.split(excludeAuthUrl, ",");
            for (String pattern : antPatterns) {
                AntPathRequestMatcher antMatcher = new AntPathRequestMatcher(pattern);
                if (antMatcher.matches(request)) {
                    if (SecurityLog.urlAuthority.isInfoEnabled()) {
                        SecurityLog.urlAuthority.info("[{}]-请求URL=[{} | {}], 静态资源开放权限", clientIP, url, httpMethod);
                    }
                    return Collections.emptyList();
                }
            }
        }
        UrlPattern urlPattern = new UrlPattern(url, httpMethod);
        final Collection<ConfigAttribute> configAttributes = requestMap.get(urlPattern);
        if (SecurityLog.urlAuthority.isInfoEnabled()) {
            SecurityLog.urlAuthority.info("[{}]-请求URL=[{} | {}], 匹配角色=[{}]", clientIP, url, httpMethod, configAttributes);
        }
        return configAttributes;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<ConfigAttribute> allAttributes = new HashSet<>();
        if (!CollectionUtils.isEmpty(requestMap)) {
            for (Map.Entry<UrlPattern, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {
                allAttributes.addAll(entry.getValue());
            }
        }
        return allAttributes;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}
